﻿using System;
using System.Collections.Generic;
using System.Linq;
using TLang.Values;

namespace TLang.Ast
{
    public class CaseNode : Node
    {
        private readonly Node _node;
        private readonly List<Tuple<Node, Node>> _elements;

        public CaseNode(Node node, List<Tuple<Node, Node>> elements, String file, int start, int end, int line, int col) : base(file, start, end, line, col)
        {
            this._node = node;
            this._elements = elements;
        }

        public override Value Interp(Scope s)
        {
            Value v = this._node.Interp(s);
            TType type = v as TType;
            IntValue n = v as IntValue;
            FloatValue f = v as FloatValue;
            StringValue str = v as StringValue;
            BoolValue b = v as BoolValue;
            if (n == null && f == null && str == null && b == null && type == null)
            {
                throw new GeneralError(_node, _node.ToString() + " must be a int float string type or bool value");
            }
            for (int i = 0; i < this._elements.Count; i++)
            {
                var tuple = this._elements[i];
                if ((tuple.Item1 is NameNode nameNode && nameNode.Id == Constants.ElseKeyword)
                        || (tuple.Item1 is KeywordNode keywordNode && keywordNode.Id == Constants.ElseKeyword))
                {
                    Node valueNode = tuple.Item2;
                    return valueNode.Interp(s);
                }
                Node testNode = tuple.Item1;
                Value testValue = testNode.Interp(s);
                if (v.Type != testValue.Type)
                {
                    throw new GeneralError(testNode, _node.ToString() + " vs " + testNode.ToString() + " must be same type");
                }

                if (type != null)
                {
                    if (testValue is TType value)
                    {
                        if (type == value)
                        {
                            return tuple.Item2.Interp(s);
                        }
                    }
                }
                else if (n != null)
                {
                    if (testValue is IntValue value)
                    {
                        if (n.Value == value.Value)
                        {
                            return tuple.Item2.Interp(s);
                        }
                    }
                }
                else if (f != null)
                {
                    if (testValue is FloatValue value)
                    {
                        if (f.Value == value.Value)
                        {
                            return tuple.Item2.Interp(s);
                        }
                    }
                }
                else if (str != null)
                {
                    if (testValue is StringValue value)
                    {
                        if (str.Value == value.Value)
                        {
                            return tuple.Item2.Interp(s);
                        }
                    }
                }
                else if (b != null)
                {
                    if (testValue is BoolValue value)
                    {
                        if (b.Value == value.Value)
                        {
                            return tuple.Item2.Interp(s);
                        }
                    }
                }
                else
                {
                    throw new GeneralError(testNode, testNode.ToString() + " must be bool type");
                }
            }
            return VoidValue.Void;
        }

        public override string ToString()
        {
            return $"({Constants.CaseKeyword} {this._node.ToString()} {string.Join(" ", this._elements.Select(a => "[" + a.Item1.ToString() + " " + a.Item2.ToString() + "]"))})";
        }
    }
}
